package com.opages.netty.demo.lesson.dark_horse2;

import com.opages.netty.demo.lesson.ByteBufferUtil;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * @author daizhong.liu
 * @create 2021-12-29 17:19
 **/
@Slf4j
public class WriteServer {
    //模拟数据太大buffer装不下分几次装载
    public static void main(String[] args) {
        try(ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
            serverSocketChannel.bind(new InetSocketAddress(8889));
            serverSocketChannel.configureBlocking(false);
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            while (true) {
                selector.select();
                Iterator<SelectionKey> iteratorKeys = selector.selectedKeys().iterator();
                while (iteratorKeys.hasNext()) {
                    SelectionKey key = iteratorKeys.next();
                    iteratorKeys.remove();
                    if(key.isAcceptable()) {
                        log.debug("客户端连接事件...");
                        SocketChannel socketChannel = serverSocketChannel.accept();
                        socketChannel.configureBlocking(false);
                        ByteBuffer buffer = ByteBuffer.allocate(32);
                        socketChannel.register(selector,SelectionKey.OP_READ,buffer);
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < 50; i++) {
                            sb.append("_"+i);
                        }
                        log.debug("向客户端写内容：\n{}\n",sb.toString());
                        ByteBuffer contentBuffer = ByteBuffer.wrap(sb.toString().getBytes(CharsetUtil.UTF_8));
                        socketChannel.write(contentBuffer);
                        if(contentBuffer.hasRemaining()) {
                            log.debug("空间不足，注册写事件，由另一个线程执行剩余的写操作.");
                            socketChannel.configureBlocking(false);
                            socketChannel.register(selector,SelectionKey.OP_WRITE,contentBuffer);
                        }
                    }
                    if(key.isWritable()) {
                        log.debug("写客户端事件...");
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer attachment = (ByteBuffer)key.attachment();
                        socketChannel.write(attachment);
                        if(!attachment.hasRemaining()) {
                            log.debug("数据写完，解除客户端写事件..");
                            key.attach(null);
                            key.interestOps(0);
                        }
                    }
                    if(key.isReadable()) {
                        log.debug("读客户端事件...");
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer attachment = (ByteBuffer)key.attachment();
                        int read = socketChannel.read(attachment);
                        if(read == -1) {
                            log.debug("客户端发送过来的内容：");
                            ByteBufferUtil.debugAll(attachment);
                        }else {
                            if (attachment.position() == attachment.limit()) {
                                ByteBuffer newBuffer = ByteBuffer.allocate(attachment.capacity() * 2);
                                // 将旧buffer中的内容放入新的buffer中
                                attachment.flip();
                                newBuffer.put(attachment);
                                // 将新buffer放到key中作为附件
                                key.attach(newBuffer);
                            }else {
                                log.debug("读取内容");
                                ByteBufferUtil.debugAll(attachment);
                            }
                        }
                    }
                }
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
